                                                                     
                                                                     
                                                                     
                                             
import japa.parser.JavaParser;

import japa.parser.ast.CompilationUnit;
import japa.parser.ast.body.ClassOrInterfaceDeclaration;
import japa.parser.ast.body.FieldDeclaration;
import japa.parser.ast.expr.AssignExpr;
import japa.parser.ast.expr.FieldAccessExpr;
import japa.parser.ast.expr.MethodCallExpr;
import japa.parser.ast.expr.ObjectCreationExpr;
import japa.parser.ast.expr.VariableDeclarationExpr;
import japa.parser.ast.visitor.VoidVisitorAdapter;

import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;


public  class ClientParser{	
	
	static BufferedWriter objects;	
	static BufferedWriter properties;	
	static BufferedWriter objectAccesses; 
	public static String [ ]objectCreationExpression=new String[1000];
	static String [ ]instanceExpr=new String[1000];	
	static int noOfObject=0;	
	static int noOfInstanceExpr=0;
	static String classInstanceExprFormat=null;
	static String[] ClassNames;
	static int numOfFiles;
	static int index; 
	
	
	public void parseClientClass(String []filesName, int num_files) throws Exception {
        		    
	   CompilationUnit[] cu=new CompilationUnit[1000];
	   FileInputStream[] in=new FileInputStream[1000];	   
	  
	   numOfFiles=num_files;
	   ClassNames=new String[numOfFiles];
	   
	   for(int j=0;j<num_files;j++){
	    	 in[j] = new FileInputStream(filesName[j]); 
	    
	    }
	   objectAccesses= new BufferedWriter(new FileWriter("InfoFiles/ObjectAccesses.txt"));
       objects = new BufferedWriter(new FileWriter("InfoFiles/Objects.txt"));       
       properties = new BufferedWriter(new FileWriter("InfoFiles/Properties.txt"));
       
        try {
        	for(int i=0;i<num_files;i++){
        	  System.out.println("File Name "+filesName[i]);
          	  cu[i]=JavaParser.parse(in[i]); 
          	
          	}
        }
        finally { 
        	
        
        	for(int i=0;i<num_files;i++){
        		
          	  in[i].close(); 
          	
          	}          
        }
    	
        
        for(int i=0;i<num_files;i++){
        	
        	index=i;
        	new ClassVisitor1().visit(cu[i], null);
        }
        
        
        
        
        for(int i=0; i<num_files; i++){
       //Get Local Class Instantiations Expression for instance, " className object = new className();"
        new LocalClassInstantiationVisitor().visit(cu[i], null);
        
       //Get Class Instantiations Expression within method for instance, " className object = new className();"
    	new ClassInstantiationExpr().visit(cu[i],null);
    	
    	//Get Object Creation Expression for instance, "object = new className();"  
    	new ObjectCreationVisitor().visit(cu[i],null);
    	
    	//Get Object Name Expressions for instance, "new className();"  		        	
    	new ObjectNameVisitor().visit(cu[i],null);
    	
    	//Get fields Accessed by an object		        	
    	new FieldAccessVisitor().visit(cu[i], null);
    	
    	//Get Methods Invoked by an object
    	new MethodInvocationVisitor().visit(cu[i],null);
    	 
     
    	
        
    	}
        objects.close();
        properties.close();
        objectAccesses.close();
       
    } 
	
	 /*
     * "visit(...)" method returns class members that are 
     * instantiating an object, For Instance, 
     * className object=new className(); changeFormat Bring 
     * this into format className object;  
     */
    
	
	private static class ClassVisitor1 extends VoidVisitorAdapter<Object> {

        @Override
		public void visit(ClassOrInterfaceDeclaration  n, Object arg) {
     	
               			
        			System.out.println("Class Visitor "+n.getName());
        			ClassNames[index]=(n.getName());
        		
				
          } 


        
	}
	
	
	private static class LocalClassInstantiationVisitor extends VoidVisitorAdapter<Object> {
    	
    	public String changeFormatToInstanceExpr(String expr)
		{	
    		//Format is:static public ClassName objectName=new ClassName()
			String instantiatedClass=null;
			String instanceName=null;			
			System.out.println("Expresssion "+expr);
			String[] names=expr.split(" ");
			for(int i=0; i<names.length; i++)
			{
				System.out.println("Expression 1 "+i+" "+names[i]);	
			}			
			int index=names.length-5;
			instantiatedClass=names[index];
			instanceName=names[index+1];
			System.out.println("Class Expr "+instantiatedClass+" "+instanceName);
			return instantiatedClass+" "+instanceName; //returns the result in the form "className object"					
				
		}		        
        @Override
		public void visit(FieldDeclaration n, Object arg) {     	
        	try {		
        		
        		String declaredFields=n.toString();        		
        		if(declaredFields.contains(" new")){
        			classInstanceExprFormat=changeFormatToInstanceExpr(n.toString());
        			instanceExpr[noOfInstanceExpr++]=new String(classInstanceExprFormat);        			
        		}		        	
			} catch (Exception e) {					
				e.printStackTrace();
			}		          
        }		        
    }

  	 /*
	 *  "visit()" method in this class visits all   
	 *  instantiating expression "className object=new className()" within methods
	 *  and stores "className object" in instanceExpr array	     
	 */
	private static class ClassInstantiationExpr extends VoidVisitorAdapter<Object> {

		
		public String changeFormatToInstanceExpr(String expr)
		{			
							
			String instantiatedClass=null;
			String instanceName=null;
			System.out.println("Expression "+expr);		
			if(expr.contains("new ")&& expr.indexOf(" ")>0&& expr.indexOf("=")>0)//Format is:ClassName objectName=new ClassName() 
			{
				instantiatedClass=expr.substring(0, expr.indexOf(" "));
				instanceName=expr.substring(expr.indexOf(" ")+1, expr.indexOf("=")-1);
			}
			else if(expr.indexOf(" ")>0 && !expr.contains(" new")) //Format is: ClassName objectName; 
			{
				instantiatedClass=expr.substring(0, expr.indexOf(" "));
				instanceName=expr.substring(expr.indexOf(" ")+1, expr.length());
			}
			//System.out.println("Expression "+instantiatedClass+" "+instanceName);
			return instantiatedClass+" "+instanceName; //returns the result in the form "className object"
		
		}        
		@Override
		public void visit(VariableDeclarationExpr  n, Object arg) {
     	
        	try {
        			
        			super.visit(n, arg);
        			classInstanceExprFormat=changeFormatToInstanceExpr(n.toString());
        			instanceExpr[noOfInstanceExpr++]=new String(classInstanceExprFormat);        			
        			
			} 	catch (Exception e) {					
						e.printStackTrace();
			}
          
        } 
	}
	/*
	 * "visit()" method in this class stores all 
	 * object creation expression "new className()" in the array objectCreationExpression
	 */	
	private static class ObjectCreationVisitor extends VoidVisitorAdapter<Object> {        
		@Override
		public void visit(ObjectCreationExpr n, Object arg) {
     	
        	try {
        			objectCreationExpression[noOfObject++]=new String(n.toString());        			
        		
			}catch(Exception e){					
						e.printStackTrace();
			}          
        }    
	}
    /*
     * "visit()" method evaluates all assignment expressions in the class and
     * uses objectCreationExpression array to find out an assignment that 
     * is used to create an instance of the object for instance object = new className();
     * "object=new className()" is the assignment expression as well as it is instantiating 
     * an instance for a class"
     */

    
	private static class ObjectNameVisitor extends VoidVisitorAdapter<Object> {
		public String changeFormatToInstanceExpr(String expr)
		{			
			
			String instantiatedClass=expr.substring(expr.indexOf("new ")+4, expr.length()-2);
			String instanceName=null;
			if(expr.indexOf("=")>0){
				instanceName=expr.substring(0, expr.indexOf("=")-1);
			}
			return instantiatedClass+" "+instanceName;
		
		}
        @Override
		public void visit(AssignExpr n, Object arg) {
     	
        	try {
        			String expression=n.toString();
        			
        			for(int i=0; i<noOfObject; i++){        			
        				if(expression.contains(objectCreationExpression[i]))   						
        				{
        					classInstanceExprFormat=changeFormatToInstanceExpr(n.toString());
        					instanceExpr[noOfInstanceExpr++]=new String(classInstanceExprFormat);        					
        					
        				}
        			}
        		
			} 	catch (Exception e) {					
						e.printStackTrace();
				}
          
        } 
    
	}

	/*
	 * "visit()" method in this class is getting fields accessed by an object "object.fieldAccessed"	  
	 */
	
	private static class FieldAccessVisitor extends VoidVisitorAdapter<Object> {
		
		 @Override
		public void visit(FieldAccessExpr  n, Object arg) {
		        	
		        	try {
		        			super.visit(n, arg);
		        			String fieldAccessed=n.toString();
		        			String field=n.getField();		        			
		        			System.out.println("Field Accessed "+ n.getField());
		        			String fieldClassName=fieldAccessed.substring(0,fieldAccessed.indexOf("."));
		        			
		        			/*Compare fieldAccessed expression "object.fieldAccessed" with "className object" expression
		        			* to make it "className.fieldAccessed"
		        			*/ 
		        			for(int i=0; i<noOfInstanceExpr; i++)
		        			{		        				
		        				String className=instanceExpr[i].substring(0, instanceExpr[i].indexOf(" "));		        				
		        				String instanceName=instanceExpr[i].substring(instanceExpr[i].indexOf(" ")+1, instanceExpr[i].length());	 
		        				if(fieldClassName.contentEquals(instanceName))
		        				{
		        									                			
			                			
			                			
			                			boolean flag=false;
		        						
		        						for(int l=0;l<numOfFiles;l++){
		        							
		        						    if(ClassNames[l]!=null && ClassNames[l].compareTo(className)==0){
		        						    	
		        						       flag=true;
		        						    
		        						    }
		        						
		        						}
			                			
			                			//if(flag==true){
			                			
			                			
			                				
			                				objects.write(className+"."+instanceName);
		        							objects.newLine();
			        						objectAccesses.write(className+"."+instanceName);
				        					objectAccesses.newLine();
				        					objectAccesses.write(className+"."+field);
				                			objectAccesses.newLine();
				        				    objectAccesses.write("End of Object");
				                			objectAccesses.newLine();	
			                		        properties.write(className+"."+field);
			        				        properties.newLine();
			                			//}
		        					
		        					
		        					}
		        				
		        			}	
		        			
						} catch (IOException e) {					
							e.printStackTrace();
						}
		          
		        	}

	

		        
		    }
		  
	 /*
	 * "visit()" method in this class is getting fields accessed by an object "object.fieldAccessed"	  
	 */
 	private static class MethodInvocationVisitor extends VoidVisitorAdapter<Object> {

		        @Override
				public void visit(MethodCallExpr  n, Object arg) {
 	        	
		        	try {
		        			super.visit(n, arg);
		        			String methodAccessed=n.toString();		        			
		        			String method=n.getName();//+"()";		        			
		        			String fieldClassName=null;
		        			if(methodAccessed.indexOf(".")>0){
		        				fieldClassName=methodAccessed.substring(0,methodAccessed.indexOf("."));
		        			}
		        					
		        			/*Compare methodAccessed expression "object.methodAccessed" with "className object" expression
		        			* to make it "className.methodAccessed"
		        			*/ 
		        			for(int i=0; i<noOfInstanceExpr; i++)
		        			{
		        				String className=instanceExpr[i].substring(0, instanceExpr[i].indexOf(" "));		        				
		        				String instanceName=instanceExpr[i].substring(instanceExpr[i].indexOf(" ")+1, instanceExpr[i].length());
		        				
		        				  
		        				if(fieldClassName!=null && instanceName!=null){	
		        				if(fieldClassName.contentEquals(instanceName))
		        				{
		        					
		        					
		        		          		
			                			
			                			boolean flag=false;
		        						
		        						for(int l=0;l<numOfFiles;l++){
		        							
		        						    if(ClassNames[l]!=null && ClassNames[l].compareTo(className)==0){
		        						    	
		        						       flag=true;
		        						    
		        						    }
		        						
		        						}
			                			
			                			
			                			//if(flag==true){
			                			
			                			
			                				
			                				
			                				
			                				
			                				objects.write(className+"."+instanceName);
			        		          		objects.newLine();
			        		              	objectAccesses.write(className+"."+instanceName);
				        					objectAccesses.newLine();
				        					objectAccesses.write(className+"."+method);
				                			objectAccesses.newLine();
				                			objectAccesses.write("End of Object");
				                			objectAccesses.newLine();	
			                		        properties.write(className+"."+method);
			                			    properties.newLine();
			                			//}
			                			
		        				}	
		        				}
		        			}
		        			
					} 	catch (IOException e) {					
								e.printStackTrace();
						}
		          
		        } 
	}		    
}
